﻿using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.ComponentModel;
using Caliburn.Micro.BikeWizard.Validation;
using Caliburn.Micro.BikeWizard.Services;
using Caliburn.Micro.BikeWizard.Data;
using Caliburn.Micro.BikeWizard.Utils;

namespace Caliburn.Micro.BikeWizard.Views
{
    public class BikeExtrasViewModel : Screen, IValidatable
    {
        #region Private Properties (Services)
        private IBikeOptionService bikeOptionService { get; set; }
        #endregion

        #region Internal Properties (Data)
        internal BikeOrder bikeOrder { get; set; }

        internal PartsGroupOption SelectedPartsGroup
        {
            get
            {
                return bikeOrder.PartsGroup;
            }
            set
            {
                bikeOrder.PartsGroup = value;
                NotifyOfPropertyChange(() => this.IsValid);
            }
        }

        internal ObservableCollection<ExtrasOption> SelectedExtras
        {
            get
            {
                return bikeOrder.Extras;
            }
        }
        #endregion

        #region Public Properties (Bindable)
        public ObservableCollection<OptionViewModel<PartsGroupOption>> AvailablePartsGroups { get; private set; }
        public ObservableCollection<OptionViewModel<ExtrasOption>> AvailableExtras { get; private set; }
        #endregion

        #region IValidatable Implementation
        public bool IsValid
        {
            get
            {
                return this.SelectedPartsGroup != null && this.SelectedExtras != null && this.SelectedExtras.Count() >= 2;
            }
        }
        #endregion

        #region Constructors
        public BikeExtrasViewModel(
            IBikeOptionService bikeOptionService,
            BikeOrder bikeOrder)
        {
            this.bikeOptionService = bikeOptionService;

            this.bikeOrder = bikeOrder;
            this.DisplayName = "Parts & extras";

            new CoroutineExecutor(GetAndCreateOptions()).Execute(null);
        }
        #endregion

        #region Private Methods
        private IEnumerable<IResult> GetAndCreateOptions()
        {
            yield return bikeOptionService.GetAvailablePartsGroups();
            yield return OptionViewModelHelper.CreateOptionViewModelList<PartsGroupOption>(
                bikeOptionService.PartsGroups,
                (result) => this.AvailablePartsGroups = new ObservableCollection<OptionViewModel<PartsGroupOption>>(result),
                (defaultPartsGroup) => this.SelectedPartsGroup = defaultPartsGroup.GetValue(),
                (selectedPartsGroup) => this.SelectedPartsGroup = selectedPartsGroup.GetValue());
            yield return bikeOptionService.GetAvailableExtras();
            yield return OptionViewModelHelper.CreateOptionViewModelList<ExtrasOption>(
                bikeOptionService.Extras,
                (result) => 
                {
                    this.AvailableExtras = new ObservableCollection<OptionViewModel<ExtrasOption>>(result); 
                },
                (defaultExtra) => 
                {
                    this.SelectedExtras.Add(defaultExtra.GetValue());
                    NotifyOfPropertyChange(() => IsValid);
                },
                (selectedExtra) =>
                {
                    if (selectedExtra.IsSelected)
                        this.SelectedExtras.Add(selectedExtra.GetValue());
                    else
                        this.SelectedExtras.Remove(selectedExtra.GetValue());

                    NotifyOfPropertyChange(() => IsValid);
                });
        }
        #endregion
    }
}
